package com.letme.framework.web.service;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;

import com.letme.common.constant.CacheConstants;
import com.letme.common.constant.HttpStatus;
import com.letme.common.core.domain.entity.WxUser;
import com.letme.common.core.domain.model.LoginUser;
import com.letme.common.core.domain.wxLogin.PhoneInfoDTO;
import com.letme.common.core.domain.wxLogin.WxMiniAppLoginResponseDTO;
import com.letme.common.core.domain.wxLogin.WxMiniAppletAccessTokenResponseDTO;
import com.letme.common.core.domain.wxLogin.WxPhoneInfoResponseDTO;
import com.letme.common.core.redis.RedisCache;
import com.letme.common.exception.BusinessException;
import com.letme.common.utils.StringUtils;
import com.letme.store.domain.WxConfig;
import com.letme.store.service.IWxConfigService;
import com.letme.store.service.IWxUserService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * 微信登录服务类
 *
 * @Description
 * @Author lock-xq
 * @Date 2024/12/21 14:57
 **/
@Component
@Slf4j
public class WxAppletLoginService {

    @Resource
    private TokenService tokenService;

    @Resource
    private IWxConfigService wxConfigService;

    @Resource
    private IWxUserService wxUserService;

    //redi缓存
    @Resource
    private RedisCache redisCache;

    /**
     * 微信小程序登录验证
     * 通过openId查询wx用户，如果用户存在并且手机号也不为空则返回用户token,否则返回204
     *
     * @param code     微信临时码
     * @param deptId   部门编号
     * @return 结果
     */
    public Object wxAppletLogin(String code, Long deptId){
        WxMiniAppLoginResponseDTO response = getWxMiniAppLoginResponse(code, deptId);
        //检查数据库种是否有个openId对应的用户，若有，则直接返回token
        WxUser wxUser = wxUserService.selectWxUserByOpenId(response.getOpenid());
        if(StringUtils.isNotNull(wxUser) && StringUtils.isNotEmpty(wxUser.getPhone())){
            LoginUser loginUser = createWxLoginUser(wxUser);
            // 生成token
            return tokenService.createToken(loginUser);
        }else{
            return HttpStatus.NO_CONTENT;
        }
    }

    /**
     * 微信小程序手机号授权登录验证
     * @param code
     * @param phoneCode
     * @param deptId
     * @return
     */
    public String wxAppletPhoneLogin(String code,String phoneCode,Long deptId){
        WxMiniAppLoginResponseDTO response = getWxMiniAppLoginResponse(code, deptId);
        String phone = getPhoneInfo(phoneCode,deptId);
        //检查数据库种是否有个openId对应的用户，若有，则直接返回token，若没有，则创建用户后再生成token并返回
        WxUser wxUser = wxUserService.selectWxUserByOpenId(response.getOpenid());
        if(StringUtils.isNull(wxUser)){
            wxUser =  new WxUser();
            wxUser.setOpenId(response.getOpenid());
            wxUser.setWxUserName("微信用户_" + phone);
            wxUser.setPhone(phone);
            wxUser.setDeptId(deptId);
        }else{
            //存在用户更新手机号
            wxUser.setPhone(phone);
        }
        wxUserService.registerWxUser(wxUser);
        LoginUser loginUser = createWxLoginUser(wxUser);
        // 生成token
        return tokenService.createToken(loginUser);
    }


    //获取当前用户的手机号
    private String getPhoneInfo(String code,Long deptId){
        //获取微信access_token
        String accessToken = getWxAccessToken(deptId);
        //通过token和code来获取用户手机号
        String url = String.format("https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s", accessToken);
        JSONObject json = new JSONObject();
        json.set("code",code);
        String res = HttpUtil.post(url,json.toString());
        WxPhoneInfoResponseDTO response = JSONUtil.toBean(res, WxPhoneInfoResponseDTO.class);
        if(StringUtils.isEmpty(response.getErrcode()) || "0".equals(response.getErrcode())){
            PhoneInfoDTO dto = JSONUtil.toBean(response.getPhoneInfo(), PhoneInfoDTO.class);
            return dto.getPhoneNumber();
        }else {
            throw new BusinessException("获取微信用户手机号失败，错误编码"+response.getErrcode()+"，错误信息："+response.getErrmsg());
        }
    }

    //获取微信公众号的全局唯一接口调用凭据
    private String getWxAccessToken(Long deptId){
        WxConfig wxConfig = getWxConfig(deptId);
        //从缓存中获取微信access_token
        String accessKey = CacheConstants.WX_ACCESS_TOKEN_KEY + wxConfig.getWxAppId();
        String accessToken = redisCache.getCacheObject(accessKey);
        if(StringUtils.isNotEmpty(accessToken)){
            return accessToken;
        }
        //微信小程序获取access_token请求地址
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + wxConfig.getWxAppId() + "&secret=" + wxConfig.getWxAppSecret();
        String res = HttpUtil.get(url);
        WxMiniAppletAccessTokenResponseDTO response = JSONUtil.toBean(res, WxMiniAppletAccessTokenResponseDTO.class);
        if(StringUtils.isEmpty(response.getErrcode())){
            //将登录信息存入缓存
            redisCache.setCacheObject(accessKey, response.getAccessToken(), response.getExpiresIn() - 100, TimeUnit.SECONDS);
            return response.getAccessToken();
        }else {
            throw new BusinessException("获取微信access_token失败，错误编码"+response.getErrcode()+"，错误信息："+response.getErrmsg());
        }
    }

    //获取微信登录openId等相关信息
    private WxMiniAppLoginResponseDTO getWxMiniAppLoginResponse(String code,Long deptId){
        WxConfig wxConfig = getWxConfig(deptId);
        //微信小程序获取openId请求地址
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type=authorization_code";
        String replaceUrl = url.replace("{0}", wxConfig.getWxAppId()).replace("{1}", wxConfig.getWxAppSecret()).replace("{2}", code);
        String res = HttpUtil.get(replaceUrl);
        WxMiniAppLoginResponseDTO response = JSONUtil.toBean(res, WxMiniAppLoginResponseDTO.class);
        if (StringUtils.isEmpty(response.getErrcode())) {
            return response;
        }else {
            throw new BusinessException("获取微信授权信息失败，错误编码"+response.getErrcode()+"，错误信息："+response.getErrmsg());
        }
    }

    //获取微信配置文件
    private WxConfig getWxConfig(Long deptId){
        WxConfig wxConfig = wxConfigService.selectWxConfigByDeptId(deptId);
        if(StringUtils.isNull(wxConfig)){
            throw new BusinessException("此公司微信登录配置信息有误,微信小程序登录失败，请联系管理员！");
        }
        return wxConfig;
    }

    //生成微信登录信息
    private LoginUser createWxLoginUser(WxUser wxUser){
        LoginUser loginUser = new LoginUser();
        loginUser.setWxUser(wxUser);
        loginUser.setDeptId(wxUser.getDeptId());
        loginUser.setUserId(wxUser.getWxUserId());
        loginUser.setOpenId(wxUser.getOpenId());
        return loginUser;
    }
}
